<!--  线 + 柱混合图 -->
<template>
  <el-card>
    <template #header>
      <div class="title">
        <div class="chart-title" @click="showBlur = !showBlur">
          {{ chartTitle }}
        </div>
        <div class="chart-title" v-if="!showBlur">
          {{ nowDate }}[{{ nowSum }}]
        </div>
        <div v-if="!showBlur">
          <el-tooltip
            effect="dark"
            content="上级数据"
            placement="bottom"
            v-if="parentDataId != 0"
          >
            <i-ep-back class="download" @click="showParentData" />
          </el-tooltip>
          <el-tooltip effect="dark" content="显示详细数据" placement="bottom">
            <i-ep-view
              class="download"
              @click="changeShowLineValue"
              :class="{ selected: isShowValue }"
            />
          </el-tooltip>
          <el-tooltip effect="dark" content="按年统计" placement="bottom">
            <i-ep-sunny
              class="download"
              @click="resetDataByYear"
              :class="{ selected: nowDataGroupType == 'year' }"
            />
          </el-tooltip>
          <el-tooltip effect="dark" content="按月统计" placement="bottom">
            <i-ep-moon
              class="download"
              @click="resetDataByMonth"
              :class="{ selected: nowDataGroupType == 'date' }"
            />
          </el-tooltip>
          <el-tooltip effect="dark" content="按天统计" placement="bottom">
            <i-ep-star
              class="download"
              @click="resetDataByDay"
              :class="{ selected: nowDataGroupType == 'day' }"
            />
          </el-tooltip>
          <el-tooltip effect="dark" content="切换选择模式" placement="bottom">
            <i-ep-switch class="download" @click="changeSelectedMode" />
          </el-tooltip>
          <el-tooltip
            effect="dark"
            content="显示所有"
            placement="bottom"
            v-if="selectedMode == 'multiple'"
          >
            <i-ep-circle-check class="download" @click="showAll" />
          </el-tooltip>
          <el-tooltip
            effect="dark"
            content="反选"
            placement="bottom"
            v-if="selectedMode == 'multiple'"
          >
            <i-ep-circle-close class="download" @click="inverseSelect" />
          </el-tooltip>
          <el-tooltip effect="dark" content="点击试试下载" placement="bottom">
            <i-ep-download class="download" @click="downloadEchart" />
          </el-tooltip>
        </div>
      </div>
    </template>

    <div :id="id" :class="className" :style="{ height, width }"></div>
    <div
      class="zhezhaox"
      :style="{ height: height, 'margin-top': '-' + height }"
      v-if="showBlur"
    >
      <div class="zhezhaox2" @click="showBlur = !showBlur"></div>
    </div>
  </el-card>
  <BillRecordDialog ref="listDialog" />
</template>

<script setup lang="ts">
const showBlur = ref<boolean>(true);
import { onMounted, defineProps } from "vue";
import { formatPrice, prefixInteger } from "@/utils/format";
import * as echarts from "echarts";
import {
  getToBillEntityByDate,
  getFromBillEntityByDate,
  getDiffBillEntityByDate,
} from "@/api/billEntity";

import { BillRecordQuery } from "@/api/billRecord/types";

import {
  BillEntityGroupByDateVO,
  BillEntityGroupQuery,
} from "@/api/billEntity/types";
// import BillRecordDialog from "../../billRecord/components/BillRecordDialog.vue";
const props = defineProps({
  id: {
    type: String,
    default: "lineChart",
  },
  className: {
    type: String,
    default: "",
  },
  width: {
    type: String,
    default: "200px",
    required: true,
  },
  height: {
    type: String,
    default: "200px",
    required: true,
  },
  bindTag: {
    type: String,
  },
  chartTitle: {
    type: String,
    required: true,
  },
  dataType: {
    type: String,
    required: true,
    default: "from",
  },
  types: {
    type: String,
  },
});
interface LegendSelected {
  [key: string]: boolean;
}

const parentDataId = ref<number>(0);
const isShowValue = ref<boolean>(false);
const selectedMode = ref<string>("multiple");
const nowDate = ref<string>("");
const nowSum = ref<string>("");

const options = {
  tooltip: {
    triggerOn: "none",
    showContent: false,
  },
  // toolbox:{
  //   show:true,
  //   feature: {
  //     magicType: {
  //       type: ['line', 'bar', 'stack']
  //     }
  //   }
  // },
  legend: {
    selected: {} as LegendSelected,
    type: "scroll",
    orient: "vertical",
    selectedMode: selectedMode.value,
    right: 10,
    top: 10,
    bottom: 20,
  },
  dataset: {
    source: [] as any[],
  },
  grid: [
    {
      left: 20,
      right: 150,
      bottom: 50,
      top: "55%",
      containLabel: true,
    },
    {
      left: 60,
      right: "50%",
      bottom: "55%",
      top: 0,
      containLabel: true,
    },
  ],
  dataZoom: [
    {
      type: "slider",
      id: "line",
      xAxisIndex: 0,
      startValue: 90,
      endValue: 100,
    },
    {
      type: "slider",
      id: "bar",
      yAxisIndex: 1,
      startValue: 0,
      endValue: 4,
      left: 30,
      filterMode: "none",
    },
  ],
  xAxis: [
    {
      type: "category",
      gridIndex: 0,
      axisPointer: {
        value: "2016-10-7",
        snap: true,
        lineStyle: {
          color: "#7581BD",
          width: 2,
        },
        label: {
          show: true,
          backgroundColor: "#7581BD",
        },
        handle: {
          show: true,
          color: "#7581BD",
          size: [35, 35],
        },
      },
      splitLine: {
        show: false,
      },
    },
    {
      type: "value",
      gridIndex: 1,
    },
  ],
  yAxis: [
    {
      gridIndex: 0,
      axisLabel: {
        formatter: function (value: number, index: number) {
          return formatPrice(value);
        },
      },
    },
    {
      type: "category",
      gridIndex: 1,
      inverse: true,
      show: false,
    },
  ],
  series: [] as any[],
  graphic: [
    // {
    //   type: "text",
    //   id: "sum",
    //   z: 100,
    //   left: "center",
    //   top: "45%",
    //   style: {
    //     text: "",
    //   },
    // },
    // {
    //   type: "text",
    //   id: "date",
    //   z: 100,
    //   left: "center",
    //   top: "50%",
    //   style: {
    //     text: "",
    //   },
    // },
  ],
};

const nowDataGroupType = ref<string>("month");
let resultData: any = {};
async function getToBillEntityGroupByDate(
  groupType: string,
  parentId?: number
) {
  const queryParams = reactive<BillEntityGroupQuery>({
    types: props.types?.split(","),
    groupType: groupType,
    parentId: parentId,
  });
  return getToBillEntityByDate(queryParams)
    .then(({ data }) => {
      resultData = data;
    })
    .finally(() => {});
}

async function getFromBillEntityGroupByDate(
  groupType: string,
  parentId?: number
) {
  const queryParams = reactive<BillEntityGroupQuery>({
    types: props.types?.split(","),
    groupType: groupType,
    parentId: parentId,
  });
  return getFromBillEntityByDate(queryParams)
    .then(({ data }) => {
      resultData = data;
    })
    .finally(() => {});
}

async function getDiffBillEntityGroupByDate(
  groupType: string,
  parentId?: number
) {
  const queryParams = reactive<BillEntityGroupQuery>({
    types: props.types?.split(","),
    groupType: groupType,
    parentId: parentId,
  });
  return getDiffBillEntityByDate(queryParams)
    .then(({ data }) => {
      resultData = data;
    })
    .finally(() => {});
}

interface EntityDict {
  name: string;
  parentId: number;
  id: number;
  children: EntityDict[];
}

let entityDictMap: any = {};
let entityNameToId: any = {};
function recurBillEntityList(
  parentId: number,
  billEntityList: BillEntityGroupByDateVO[]
) {
  let entityList: EntityDict[] = [];
  billEntityList.forEach((entity) => {
    if (entity.parentId == parentId) {
      let children: EntityDict[] = recurBillEntityList(
        entity.id,
        billEntityList
      );
      let entityDict: EntityDict = {
        name: entity.name,
        parentId: entity.parentId,
        id: entity.id,
        children: children,
      };
      entityList.push(entityDict);
      entityDictMap[entity.id] = entityDict;
    }
  });
  return entityList;
}

let entityDicts: EntityDict[] = [];

function getNumByNameAndDate(name: string, date: string, numDict: any) {
  if (numDict[name] != undefined && numDict[name][date] != undefined) {
    return numDict[name][date];
  }
  return 0;
}

function getAllNum(root: EntityDict, date: string, numDict: any) {
  let sum: number = getNumByNameAndDate(root.name, date, numDict);
  root.children.forEach((element) => {
    sum += getAllNum(element, date, numDict);
  });
  return sum;
}

let dates: string[] = [];
let datas: any = {};
async function resetData(groupType: string, parentId?: number) {
  nowDataGroupType.value = groupType;
  parentId = parentId ? parentId : 0;
  if (props.dataType == "from") {
    await getFromBillEntityGroupByDate(groupType, parentId);
  } else if (props.dataType == "to") {
    await getToBillEntityGroupByDate(groupType, parentId);
  } else {
    await getDiffBillEntityGroupByDate(groupType, parentId);
  }

  datas = {};
  dates = [];
  const entityIds: number[] = [];
  const entities: BillEntityGroupByDateVO[] = [];
  for (let index = 0; index < resultData.length; index++) {
    const element: BillEntityGroupByDateVO = resultData[index];
    const tags: string[] = element.tagNames ? element.tagNames.split(",") : [];
    if (!props.bindTag || tags.includes(props.bindTag)) {
      if (element.date != undefined && !dates.includes(element.date)) {
        dates.push(element.date);
      }
      if (!entityIds.includes(element.id)) {
        entityIds.push(element.id);
        entities.push(element);
        entityNameToId[element.name] = element.id;
      }

      let name = element.name;
      if (!datas[name]) {
        datas[name] = {};
      }

      if (!datas[name][element.date]) {
        datas[name][element.date] = element.num;
      }
    }
  }
  entityDictMap = {};
  entityDicts = recurBillEntityList(parentId, entities);

  dates.sort();
  setChartByParentId(parentId);
}

function setChartByParentId(parentId: number) {
  chart.value.clear();
  chart.value.setOption(options);
  let optionsParams = {
    dataset: {
      source: [] as any,
    },
    series: [] as any,
    legend: {
      selected: {} as any,
      data: [] as any,
    },
    dataZoom: [
      {
        id: "line",
        startValue: 0,
        endValue: 0,
      },
      {
        id: "bar",
        startValue: 0,
        endValue: 4,
      },
    ],
  };

  optionsParams.dataset.source.push([...["date"], ...dates]);

  let nowParentEntity: EntityDict = entityDictMap[parentId];
  let entities: EntityDict[] = [];
  if (nowParentEntity == undefined) {
    entities = entityDicts;
    parentDataId.value = 0;
  } else {
    entities = nowParentEntity.children;
    parentDataId.value = nowParentEntity.id;
  }

  entities.forEach((entity) => {
    let key: string = entity.name;
    optionsParams.legend.data.push({ name: key });
    const series: any = {
      id: key,
      name: key,
      type: "line",
      xAxisIndex: 0,
      yAxisIndex: 0,
      seriesLayoutBy: "row",
      smooth: true,
      emphasis: { focus: "series" },
      label: {
        show: isShowValue.value,
        fontSize: 10,
        position: "top",
        formatter: function (params: any, index: number) {
          let value = params.value[params.encode.y[0]];
          return formatPrice(value);
        },
      },
    };
    const nums: any[] = [key];
    for (let index = 0; index < dates.length; index++) {
      let date = dates[index];
      let num = getAllNum(entity, date, datas);
      nums.push(num);
    }
    optionsParams.dataset.source.push(nums);
    optionsParams.series.push(series);
  });

  let theLength = dates.length;
  optionsParams.dataZoom[0].startValue = Math.max(0, theLength - 11);
  optionsParams.dataZoom[0].endValue = theLength;

  // optionsParams.dataZoom[1].startValue = Math.max(0, theLength - 11);
  // optionsParams.dataZoom[1].endValue = theLength;
  chart.value.setOption(optionsParams);

  createPie();
  createBar();
  // 默认显示最后数据
  changePie(nowDimension);
  changeBar(nowDimension);
}

function showParentData() {
  let nowParentEntity: EntityDict = entityDictMap[parentDataId.value];
  if (nowParentEntity == undefined) {
    setChartByParentId(0);
  } else {
    setChartByParentId(nowParentEntity.parentId);
  }
}

let nowPieDataIndex = 0;
const changeSum = () => {
  let nowOptions = chart.value.getOption();
  let sum = 0;
  let selected = nowOptions.legend[0].selected;
  for (let i = 1; i < nowOptions.dataset[0].source.length; i++) {
    let name = nowOptions.dataset[0].source[i][0];
    if (selected[name] != false) {
      sum += nowOptions.dataset[0].source[i][nowPieDataIndex];
    }
  }

  // const param: any = {
  //   graphic: [
  //     {
  //       id: "sum",
  //       style: {
  //         text: formatPrice(sum),
  //       },
  //     },
  //   ],
  // };
  nowSum.value = formatPrice(sum);
  // chart.value.setOption(param);
};

const changePie = (index: number) => {
  let nowOptions = chart.value.getOption();
  if (index < 0) {
    index = nowOptions.dataset[0].source[0].length + index;
  }
  nowPieDataIndex = index;
  const param: any = {
    series: {
      id: "pie",
      label: {
        formatter: (params: any) => {
          return (
            params.name +
            ": " +
            formatPrice(params.data[index]) +
            " (" +
            params.percent +
            "%)"
          );
        },
      },
      encode: {
        value: index,
        tooltip: index,
      },
    },
    // graphic: [
    //   {
    //     id: "date",
    //     style: {
    //       text: nowOptions.dataset[0].source[0][index],
    //     },
    //   },
    // ],
  };
  chart.value.setOption(param);
  nowDate.value = nowOptions.dataset[0].source[0][index];
  changeSum();
};

const changeBar = (index: number) => {
  let nowOptions = chart.value.getOption();
  if (index < 0) {
    index = nowOptions.dataset[0].source[0].length + index;
  }
  nowPieDataIndex = index;
  const param: any = {
    series: {
      id: "bar",
      label: {
        formatter: (params: any) => {
          return params.name + ": " + formatPrice(params.data[index]);
        },
      },
      encode: {
        // y:
        x: index,
        // tooltip: index,
      },
    },
  };
  chart.value.setOption(param);
};

function createPie() {
  let pieParams = {
    series: [
      {
        type: "pie",
        id: "pie",
        radius: ["20%", "30%"],
        center: ["75%", "20%"],
        emphasis: {
          focus: "self",
        },
        label: {
          formatter: "{b}: {@2012} ({d}%)",
        },
        encode: {
          itemName: "date",
          value: "2012",
          tooltip: "2012",
        },
        minAngle: 0,
        minShowLabelAngle: 0.0001,
      },
    ],
  };
  chart.value.setOption(pieParams);
}

function createBar() {
  let pieParams = {
    series: [
      {
        type: "bar",
        id: "bar",
        xAxisIndex: 1,
        yAxisIndex: 1,
        realtimeSort: true,
        emphasis: {
          focus: "self",
        },
        label: {
          show: true,
          position: "inside",
        },
      },
    ],
  };
  chart.value.setOption(pieParams);
}

const chart = ref<any>("");
let nowDimension = -1;
async function createChart() {
  // 图表初始化
  chart.value = markRaw(
    echarts.init(document.getElementById(props.id) as HTMLDivElement)
  );

  chart.value.on("updateAxisPointer", function (event: any) {
    const xAxisInfo = event.axesInfo[0];
    if (xAxisInfo) {
      nowDimension = xAxisInfo.value + 1;
      changePie(nowDimension);
      changeBar(nowDimension);
    }
  });

  chart.value.on("legendselectchanged", function (event: any) {
    changeSum();
  });

  chart.value.on("click", function (event: any) {
    if (event.data) {
      let id = entityNameToId[event.data[0]];
      if (id) {
        if (entityDictMap[id].children.length > 0) {
          setChartByParentId(id);
        } else {
          openDialog(id);
        }
      }
    }
  });
  await resetData("month");

  // 大小自适应
  window.addEventListener("resize", () => {
    chart.value.resize();
  });
}

onMounted(() => {
  createChart();
});
const downloadEchart = () => {
  // 获取画布图表地址信息
  const img = new Image();
  img.src = chart.value.getDataURL({
    type: "png",
    pixelRatio: 1,
    backgroundColor: "#fff",
  });
  // 当图片加载完成后，生成 URL 并下载
  img.onload = () => {
    const canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;
    const ctx = canvas.getContext("2d");
    if (ctx) {
      ctx.drawImage(img, 0, 0, img.width, img.height);
      const link = document.createElement("a");
      link.download = props.chartTitle + `.png`;
      link.href = canvas.toDataURL("image/png", 0.9);
      document.body.appendChild(link);
      link.click();
      link.remove();
    }
  };
};

const changeSelectedMode = () => {
  if (selectedMode.value == "multiple") {
    selectedMode.value = "single";
  } else {
    selectedMode.value = "multiple";
  }

  const params: any = {
    legend: {
      selectedMode: selectedMode.value,
    },
  };
  chart.value.setOption(params);
  if (selectedMode.value == "multiple") {
    showAll();
    changeShowLineValue(false);
  } else {
    changeShowLineValue(true);
  }
};

const inverseSelect = () => {
  chart.value.dispatchAction({
    type: "legendInverseSelect",
  });
};

const showAll = () => {
  chart.value.dispatchAction({
    type: "legendAllSelect",
  });
};

const changeShowLineValue = (isShow?: boolean) => {
  if (typeof isShow != "boolean") {
    isShowValue.value = !isShowValue.value;
  } else {
    isShowValue.value = isShow;
  }
  const params: any = {
    series: [],
  };
  let nowOptions = chart.value.getOption();
  for (const key in nowOptions.series) {
    let data = nowOptions.series[key];
    if (data.type == "line") {
      params.series.push({
        id: data.id,
        label: {
          show: isShowValue.value,
        },
      });
    }
  }
  chart.value.setOption(params);
};

const resetDataByYear = async () => {
  await resetData("year");
  nowDimension = -1;
  changePie(nowDimension);
  changeBar(nowDimension);
};

const resetDataByMonth = async () => {
  await resetData("month");
  nowDimension = -1;
  changePie(nowDimension);
  changeBar(nowDimension);
};

const resetDataByDay = async () => {
  await resetData("day");
  nowDimension = -1;
  changePie(nowDimension);
  changeBar(nowDimension);
};

/**
 * 打开弹窗
 *
 */
const listDialog = ref();
function openDialog(id: number) {
  const params: BillRecordQuery = reactive<BillRecordQuery>({
    pageNum: 1,
    pageSize: 10,
  });

  if (props.dataType == "from") {
    params.fromEntityId = id;
  } else if (props.dataType == "to") {
    params.toEntityId = id;
  } else {
    params.fromOrToEntityId = id;
  }
  const date: string[] = nowDate.value.split("/");
  if (nowDataGroupType.value == "year") {
    params.startTime = date[0] + "-01-01";
    params.endTime = date[0] + "-12-31";
  } else if (nowDataGroupType.value == "month") {
    var month = parseInt(date[1]); // 表示当前月份的变量
    var year = parseInt(date[0]); //年份, 这个根据实际情况而定，是给定的值，还是根据当前时间来获取年份。
    var newDate = new Date(year, month - 1, 32); // 根据月份设置日期
    var day = 32 - newDate.getDate(); // 根据设置的日期来获取当前月份的天数。
    params.startTime = date.join("-") + "-01";
    params.endTime = date.join("-") + "-" + prefixInteger(day, 2);
  } else {
    params.startTime = date.join("-");
    params.endTime = date.join("-");
  }

  listDialog.value.openDialog(params);
}
</script>
<style lang="scss" scoped>
.title {
  display: flex;
  justify-content: space-between;

  .download {
    cursor: pointer;

    &:hover {
      color: #409eff;
    }
  }

  .selected {
    color: #409eff;
  }
}

.zhezhaox {
  position: relative;
  width: 100%;

  .zhezhaox2 {
    position: absolute;
    inset: 0;
    background: rgb(255 255 255 / 5%);
    backdrop-filter: blur(5px);
    // z-index: 1000;
  }
}
</style>
